package edu.isistan.matching.adapters;

import java.util.Hashtable;
import java.util.Set;

import edu.isistan.metamodel.DataType;


/**
 * Adaptador base que define la funcionalidad que deberan implementar los
 * adaptadores
 * 
 * @author Mariano
 * 
 */
public abstract class PrimitiveTypeAdapter {

	/**
	 * Tipo del elemento que se esta adaptando
	 */
	protected DataType type;

	/**
	 * Valor del elemento que se esta adaptando
	 */
	protected Object value;

	/**
	 * Valida si un elemento es 100% compatible con el elemento que se esta
	 * adaptando
	 * 
	 * @param element
	 *            tipo del elemento a convertir
	 * @return boolean con la validacion
	 */

	protected String COMMENT_NO_COMPABILITY = "TODO: REALIZAR CONVERSIÓN";

	static String CODE_MASK = "XXX";
	
	public boolean isFullyCompatible(DataType element) {
		return getFullyCompatibles().contains(element.getType());
	}

	/**
	 * Valida si un elemento es compatible con perdida con el elemento que se
	 * desea adaptar
	 * 
	 * @param element
	 *            tipo del elemento a convertir
	 * @return boolean con la validacion
	 */
	public boolean isLoosyCompatible(DataType element) {
		return getLoosyCompatibles().contains(element.getType());
	}

	/**
	 * Valida si un element es incompatible con el elemento que se desea adaptar
	 * 
	 * @param element
	 *            tipo de elemento a convertir
	 * @return boolean con la validacion
	 */
	public boolean isIncompatible(DataType element) {
		return !isFullyCompatible(element) && !isLoosyCompatible(element);
	}

	/**
	 * Convierte del valor de un elemento pasado por parametro al
	 * correspondiente del adaptador
	 * 
	 * @param value
	 *            valor del objeto a convertir
	 * @return valor convertido
	 */
	public abstract Object valueof(Object value);

	/**
	 * Convierte el valor del elemento al valor de un tipo pasado por parametro
	 * 
	 * @param element
	 *            tipo de elemento al cual convertir
	 * @return valor convertido
	 */
	public abstract Object toValue(DataType element);

	public DataType getType() {
		return type;
	}

	public void setType(DataType type) {
		this.type = type;
	}

	public Object getValue() {
		return value;
	}

	public void setValue(Object value) {
		this.value = value;
	}

	/**
	 * Retorna los elementos compatibles al tipo
	 * 
	 * @return
	 */
	public abstract Set<String> getFullyCompatibles();

	/**
	 * Retorna los elementos compatibles con perdida al tipo
	 * 
	 * @return
	 */
	public abstract Set<String> getLoosyCompatibles();

	/**
	 * Retorna los codigos de conversion para el tipo primitivo
	 *
	 */
	public abstract Hashtable<String, String> getLibraryCode();


	public String codeConverter(String typeSource, String typeTarget, String codeToConvert) {
	
		String codigo = getLibraryCode().get(typeTarget);
		if (codigo != null) {
			codigo = codigo.replaceAll(CODE_MASK, " " + codeToConvert + " ");
		} else {
			codigo ="/*"+ COMMENT_NO_COMPABILITY + ", no se pudo convertir el tipo '"+typeTarget+"' al tipo '"+typeSource +"' */ " + codeToConvert;
		}
		return codigo;
	}

	/**
	 * Indica si los tipos pasados por parametros pueden ser convertidos
	 * implicitamente.
	 */
	public boolean canBeImplicitConversion(String type1, String type2) {
		return false;
	}
}
